// ------------------------------------------------------------------------------------------
// Licensed by Interprise Solutions.
// http://www.InterpriseSolutions.com
// For details on this license please visit  the product homepage at the URL above.
// THE ABOVE NOTICE MUST REMAIN INTACT.
// ------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Security;
using System.Xml.Serialization;
using Interprise.Facade.Base.Customer;
using Interprise.Framework.Base.DatasetGateway.CRM;
using Interprise.Framework.Base.DatasetGateway.Customer;
using InterpriseSuiteEcommerceCommon.DataAccess;
using InterpriseSuiteEcommerceCommon.DTO;
using InterpriseSuiteEcommerceCommon.Extensions;

namespace InterpriseSuiteEcommerceCommon
{
    /// <summary>
    /// Customer object info is rebuilt off of session["CustomerID"]!!!! This is created in AppLogic.SessionStart or other places
    /// this is the ONLY data stored in session and is server farm safe
    /// </summary>
    [Serializable]
    public class Customer : IIdentity
    {
        public enum BusinessTypes
        {

            Retail,
            WholeSale
        }

        #region Variable Declaration

        public static readonly String ro_LocaleSettingCookieName = "LocaleSetting";
        public static readonly String ro_CurrencySettingCookieName = "CurrencySetting";

        // referrer is handled specially (to get the very first one!)
        public static readonly String ro_ReferrerCookieName = "Referrer";
        public static readonly String ro_AffiliateCookieName = "AffiliateID";
        private string m_CustomerCode;
        private bool m_HasCustomerRecord;
        private Guid m_contactGUID;
        private String m_AffiliateID;
        private String m_LocaleSetting;
        private String m_CurrencyCode;
        private String m_Phone;
        private String m_EMail;
        private bool m_OKToEMail;
        private String m_Password;
        private String m_FirstName;
        private String m_LastName;
        private String m_PricingMethod;
        private string m_Notes;
        private String m_DefaultPrice = String.Empty;
        private String m_LastIPAddress;
        private DateTime m_SubscriptionExpiresOn;
        private string m_DefaultBilToCode;
        private string m_DefaultShipToCode;
        private int m_SkinID;
        private CustomerSession m_CustomerSession;
        private int m_CurrentSessionID;
        private DateTime m_LastActivity;
        private string m_Roles = string.Empty;
        private bool m_IsRegistered;
        private CultureInfo _culture = null;
        private String m_PricingLevel;
        private String m_CouponCode;
        private string _warehouseCode = string.Empty;
        private bool _allowBackOrder = false; // should default to false especially on anonymous users
        private string _paymentTermGroup = string.Empty;
        private string _paymentTermCode = string.Empty;
        private string _paymentMethod = string.Empty;
        private string _anonymousCustomerCode = string.Empty;
        private string _anonymousShipToCode = string.Empty;
        private string _languageCode = string.Empty;
        private bool _oKToEMail = false;
        private bool _over13 = false;
        private bool _iscustomerAnonUpdated = false;
        private string _salutation = string.Empty;
        private Address _primaryBillingAddress = null;
        private Address _primaryShippingAddress = null;
        private bool m_Active = true;
        private List<Address> _billingAddresses = new List<Address>();
        private List<Address> _shippingAddresses = new List<Address>();
        private string _taxNumber = string.Empty;
        private BusinessTypes _businessType = BusinessTypes.Retail;

        private decimal _discount = decimal.Zero;
        private decimal _pricingPercent = decimal.Zero;
        private string _discountType = string.Empty;
        private string _contactCode = string.Empty;
        private string _contactFullName = string.Empty;
        private string _sourceCode = string.Empty;
        private string _productFilterID = string.Empty;
        private string _defaultBillingCode = string.Empty;
        private string _defaultShippingCode = string.Empty;
        private string _discountBand = string.Empty;

        private string _loggedContactCode = string.Empty;
        private bool m_IsCreditOnHold = false;

        #region Delegates

        public delegate String GetDefault();
        public delegate String Validate(String TheVal);

        #endregion


        public static String GetDefaultSkin()
        {
            return AppLogic.AppConfig("DefaultSkinID");
        }


        public static String ValidateSkin(String SkinID)
        {
            if (SkinID.Length != 0 && CommonLogic.IsInteger(SkinID))
            {
                return SkinID;
            }
            return GetDefaultSkin();
        }

        public static String GetDefaultAffiliate()
        {
            return "0";
        }

        public string SourceCode
        {
            get
            {
                return "Internet"; //I'm thinking if we should use the data from the SystemSourceCode table (Speed Issue)
            }
            set
            {
                this._sourceCode = value;
            }
        }

        public string ContactCode
        {
            get { return _contactCode; }
            set { _contactCode = value; }
        }


        public string ContactFullName
        {
            get { return _contactFullName; }
            set { _contactFullName = value; }
        }

        public Address PrimaryBillingAddress
        {
            get
            {
                if (null == _primaryBillingAddress)
                {
                    LoadPrimaryBillingAddress();
                }

                return _primaryBillingAddress;
            }
            set
            {
                _primaryBillingAddress = value;

                if (_billingAddresses.Count > 0)
                {
                    _billingAddresses.Insert(0, _primaryBillingAddress);
                }
            }
        }

        public Address PrimaryShippingAddress
        {
            get
            {
                if (_primaryShippingAddress == null || (_primaryShippingAddress.AddressID == ""))
                {
                    LoadPrimaryShippingAddress();
                }

                return _primaryShippingAddress;
            }
            set
            {
                _primaryShippingAddress = value;

                if (_shippingAddresses.Count > 0)
                {
                    _shippingAddresses.Insert(0, _primaryShippingAddress);
                }
            }
        }

        private void LoadPrimaryBillingAddress()
        {
            _primaryBillingAddress = Address.Get(this, AddressTypes.Billing, string.Empty);
        }

        private void LoadPrimaryShippingAddress()
        {
            _primaryShippingAddress = Address.Get(this, AddressTypes.Shipping, string.Empty);
        }

        public List<Address> BillingAddresses
        {
            get
            {
                if (_billingAddresses.Count == 0)
                {
                    LoadBillingAddresses();
                }

                return _billingAddresses;
            }
        }

        public bool HasMoreThanOneBillingAddress
        {
            get { return this.BillingAddresses.Count > 1; }
        }

        public bool HasMoreThanOneShippingAddress
        {
            get { return this.ShippingAddresses.Count > 1; }
        }

        private void LoadBillingAddresses()
        {
            _billingAddresses.Add(this.PrimaryBillingAddress);

            List<string> otherAddressIds = new List<string>();

            // load others...

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, "SELECT CreditCardCode FROM CustomerCreditCard with (NOLOCK) WHERE IsActive = 1 AND CustomerCode = {0} AND CreditCardCode <> {1}", DB.SQuote(this.CustomerCode), DB.SQuote(PrimaryBillingAddress.AddressID)))
                {
                    while (reader.Read())
                    {
                        otherAddressIds.Add(DB.RSField(reader, "CreditCardCode"));
                    }
                }
            }

            foreach (string addressId in otherAddressIds)
            {
                Address otherAddress = new Address();
                otherAddress.LoadByCustomer(this, AddressTypes.Billing, addressId);

                _billingAddresses.Add(otherAddress);
            }
        }

        public List<Address> ShippingAddresses
        {
            get
            {
                if (_shippingAddresses.Count == 0)
                {
                    LoadShippingAddresses();
                }

                return _shippingAddresses;
            }
        }

        public string ProductFilterID
        {
            get
            {
                return _productFilterID;
            }
            set
            {
                _productFilterID = value;
            }

        }

        public string DefaultBillingCode
        {
            get
            {
                return _defaultBillingCode;
            }
            set
            {
                _defaultBillingCode = value;
            }

        }

        public string DefaultShippingCode
        {
            get
            {
                return _defaultShippingCode;
            }
            set
            {
                _defaultShippingCode = value;
            }

        }

        private void LoadShippingAddresses()
        {
            _shippingAddresses.Add(this.PrimaryShippingAddress);

            List<string> otherAddressIds = new List<string>();

            // load others...
            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, "SELECT ShipToCode FROM CustomerShipTo with (NOLOCK) WHERE IsActive = 1 AND CustomerCode = {0} AND ShipToCode <> {1}", DB.SQuote(this.CustomerCode), DB.SQuote(this.PrimaryShippingAddress.AddressID)))
                {
                    while (reader.Read())
                    {
                        otherAddressIds.Add(DB.RSField(reader, "ShipToCode"));
                    }
                }
            }

            foreach (string addressId in otherAddressIds)
            {
                var otherAddress = new Address();
                otherAddress.LoadByCustomer(this, AddressTypes.Shipping, addressId);

                _shippingAddresses.Add(otherAddress);
            }
        }

        public Address GetRegistryItemShippingAddress(string registryItemShippingAddressId, Guid? giftRegistryID)
        { 
            var registryItemShippingAddress = new Address();
            registryItemShippingAddress.LoadByCustomer(this, AddressTypes.Shipping, registryItemShippingAddressId, giftRegistryID);
            registryItemShippingAddress.RegistryID = giftRegistryID;
            registryItemShippingAddress.RegistryTextSelection = AppLogic.GetString("giftregistry.aspx.11", SkinID, LocaleSetting);
            return registryItemShippingAddress;
        }

        public static String ValidateAffiliate(String AffiliateID)
        {
            // choosing to only validate that it's an integer, not that it actually is defined as an affiliate
            // if you wanted to, you could validate against the affilate table using the code shown below, but we're
            // choosing not to do that right now, as customers use affiliateid flags in a number of various ways.
            if (AffiliateID.Length != 0 && CommonLogic.IsInteger(AffiliateID))
            {
                return AffiliateID;
            }
            return "0";
        }


        #endregion

        public bool Active
        {
            get { return m_Active; }
        }

        public bool IsCreditOnHold
        {
            get { return m_IsCreditOnHold; }
            set { m_IsCreditOnHold = value; }
        }


        public int CurrentSessionID
        {
            get { return m_CurrentSessionID; }
        }

        public string WarehouseCode
        {
            get { return _warehouseCode; }
            set { _warehouseCode = value; }
        }

        public string PaymentTermGroup
        {
            get { return _paymentTermGroup; }
            set { _paymentTermGroup = value; }
        }

        public string PaymentTermCode
        {
            get { return _paymentTermCode; }
            set { _paymentTermCode = value; }
        }

        public string LanguageCode
        {
            get { return _languageCode; }
            set { _languageCode = value; }
        }

        public bool IsUnregisteredAnonymous
        {
            get { return !HasCustomerRecord; }
        }

        public CultureInfo Culture
        {
            get { return _culture; }
        }

        public bool IsOKToEMail
        {
            get { return _oKToEMail; }
            set { _oKToEMail = value; }
        }

        public bool IsOver13
        {
            get { return _over13; }
            set { _over13 = value; }
        }

        public bool IsUpdatedAnonCustRecord
        {
            get { return _iscustomerAnonUpdated; }
            set { _iscustomerAnonUpdated = value; }
        }

        public string TaxNumber
        {
            get { return _taxNumber; }
            set { _taxNumber = value; }
        }

        public BusinessTypes BusinessType
        {
            get { return _businessType; }
            set { _businessType = value; }
        }

        public string Salutation
        {
            get { return _salutation; }
            set { _salutation = value; }
        }

        public VatDefaultSetting VATSettingRaw
        {
            get
            {
                VatDefaultSetting xVat = VatDefaultSetting.Exclusive;

                int raw = (int)VatDefaultSetting.Exclusive;

                if (this.HasCustomerRecord)
                {
                    raw = ThisCustomerSession.SessionUSInt("VAT.DefaultSetting");
                }
                else
                {
                    raw = AppLogic.AppConfigUSInt("VAT.DefaultSetting");
                }

                if (raw == (int)VatDefaultSetting.Exclusive || raw == (int)VatDefaultSetting.Inclusive)
                {
                    xVat = (VatDefaultSetting)raw;
                }
                else
                {
                    xVat = VatDefaultSetting.Exclusive;
                }

                return xVat;
            }
            set
            {
                if (this.HasCustomerRecord)
                {
                    ThisCustomerSession.SetVal("VAT.DefaultSetting", ((int)value).ToString());
                }
            }
        }

        public VatDefaultSetting VATSettingReconciled
        {
            get
            {
                VatDefaultSetting xVat = (VatDefaultSetting)AppLogic.AppConfigUSInt("VAT.DefaultSetting");

                if (AppLogic.AppConfigBool("VAT.AllowCustomerToChooseSetting"))
                {
                    xVat = this.VATSettingRaw;
                }

                return xVat;
            }
        }

        public static String ValidateVATSetting(String VATSettingID)
        {
            if (!AppLogic.AppConfigBool("VAT.AllowCustomerToChooseSetting"))
            {
                return AppLogic.AppConfigUSInt("VAT.DefaultSetting").ToString();
            }
            if (VATSettingID == "1" || VATSettingID == "2")
            {
                return VATSettingID;
            }

            return AppLogic.AppConfigUSInt("VAT.DefaultSetting").ToString();
        }

        protected Customer(Guid contactGUID)
        {
            m_contactGUID = contactGUID;
            _culture = System.Threading.Thread.CurrentThread.CurrentCulture.Clone() as CultureInfo;
        }

        /// <summary>
        /// Returns true is email is in use.  
        /// </summary>
        /// <param name="email">The email to search for.</param>
        /// <param name="CustomerCode">Pass zero for to find the email addres for any user, pass a customerid to exclude this customer from the search.</param>
        /// <returns></returns>
        /// 
        public static bool EmailInUse(string email, string CustomerCode)
        {
            return (email != "" && DB.GetSqlN("SELECT COUNT(*) AS N FROM Customer C with (NOLOCK) LEFT JOIN CrmContact CC with (NOLOCK) ON C.CustomerCode = CC.EntityCode WHERE CC.UserName=" + DB.SQuote(email) + " AND C.CustomerCode <> " + DB.SQuote(CustomerCode)) > 0);
        }

        public static bool IsEmailAlreadyInUse(string email)
        {
            return IsEmailAlreadyInUse(email, Guid.Empty);
        }

        private static bool IsEmailAlreadyInUse(string email, Guid notByThisCustomer)
        {
            string sWebSiteCode = InterpriseHelper.ConfigInstance.WebSiteCode;
            string checkEmailAvailabilityQuery =
            string.Format(
                "SELECT COUNT(*) AS N FROM Customer c with (NOLOCK) INNER JOIN CRMContact cc with (NOLOCK) ON c.CustomerCode = cc.EntityCode AND cc.[Type] = 'CustomerContact' AND cc.UserName = {0} {1} {2}",
                DB.SQuote(email),
                CommonLogic.IIF(
                    Guid.Empty.Equals(notByThisCustomer),
                    string.Empty,
                    string.Format("AND cc.ContactGUID <> '{0}'", notByThisCustomer)
                ),
                string.Format("AND cc.WebSiteCode='{0}'", sWebSiteCode)
            );

            return DB.GetSqlN(checkEmailAvailabilityQuery) > 0;
        }

        public bool CanChangeEmailTo(string otherEmail)
        {
            return !IsEmailAlreadyInUse(otherEmail, this.ContactGUID);
        }



        public static Customer Find(Guid customerGuid)
        {
            Customer foundCustomer = new Customer(customerGuid);
            foundCustomer.Init();

            if (!foundCustomer.HasCustomerRecord)
            {
                // this routine requires that the customer is recorded in the db.. 
                return null;
            }

            return foundCustomer;
        }

        public static Customer New()
        {
            return new Customer(Guid.Empty);
        }

        public static Customer MakeAnonymous()
        {
            Customer cust = new Customer(Guid.Empty);
            cust.Init();
            return cust;
        }

        public string GetAnonEmail()
        {
            string email = string.Empty;

            if (!this.IsRegistered && this.HasCustomerRecord)
            {
                bool customerRecordExists = false;

                using (SqlConnection con = DB.NewSqlConnection())
                {
                    con.Open();
                    using (IDataReader reader = DB.GetRSFormat(con, "SELECT Email FROM EcommerceAddress with (NOLOCK) WHERE CustomerID = {0}", this.CustomerCode))
                    {
                        customerRecordExists = reader.Read();

                        if (customerRecordExists)
                        {
                            email = DB.RSField(reader, "Email");
                        }
                    }
                }
            }

            return email;
        }

        private void Init()
        {
            // Setup Default values...
            if (HttpContext.Current != null)
            {
                m_AffiliateID = CommonLogic.CookieCanBeDangerousContent(ro_AffiliateCookieName, true);
                m_LastIPAddress = CommonLogic.ServerVariables("REMOTE_ADDR");
            }
            else
            {
                m_AffiliateID = string.Empty;
                m_LastIPAddress = string.Empty;
            }
            m_IsRegistered = false;

            // NOTE:
            //  This routine handles 3 cases
            //  1. a valid customercode was passed, it's either a registered customer or
            //  2. An anonymous customer with a record on the EcommerceCustomer table
            //  3. It's not a recorded customer and will carry the settings of the anonymous customer defined for the WebSite.
            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, "EXEC EcommerceGetCustomer @ContactGuid = {0}, @WebsiteCode = {1}, @CurrentDate = {2}",
                                                                    DB.SQuote(this.ContactGUID.ToString()),
                                                                    DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode),
                                                                    DB.SQuote(Localization.ToDBDateTimeString(DateTime.Now))))
                {
                    reader.Read(); // <- This is guaranteed to read a value....

                    // Cases would be
                    //  1. This is a registered customer and has a record in the customer table
                    //  2. This isn't yet a registered customer, but is an anonymous and has a record in the anon table

                    m_contactGUID = new Guid(DB.RSFieldGUID(reader, "ContactGuid"));
                    m_IsRegistered = DB.RSFieldBool(reader, "IsRegistered");
                    m_HasCustomerRecord = m_IsRegistered || DB.RSFieldBool(reader, "HasAnonymousRecord");
                    CustomerCode = DB.RSField(reader, "CustomerCode");
                    m_CurrencyCode = DB.RSField(reader, "CurrencyCode");
                    PrimaryBillingAddressID = DB.RSField(reader, "DefaultBillToCode");
                    PrimaryShippingAddressID = DB.RSField(reader, "DefaultShipToCode");
                    DefaultPrice = DB.RSField(reader, "DefaultPrice");
                    PricingMethod = DB.RSField(reader, "PricingMethod");
                    PricingLevel = DB.RSField(reader, "PricingLevel");
                    PricingPercent = DB.RSFieldDecimal(reader, "PricingPercent");
                    DiscountType = DB.RSField(reader, "DiscountType");
                    Discount = DB.RSFieldDecimal(reader, "Discount");
                    DiscountBand = DB.RSField(reader, "DiscountBand");
                    PaymentTermGroup = DB.RSField(reader, "PaymentTermGroup");
                    PaymentTermCode = DB.RSField(reader, "PaymentTermCode");
                    _paymentMethod = DB.RSField(reader, "PaymentMethod");
                    DefaultBillingCode = DB.RSField(reader, "DefaultBillingCode");
                    DefaultShippingCode = DB.RSField(reader, "DefaultShippingCode");
                    LocaleSetting = DB.RSField(reader, "LocaleSetting");
                    Notes = DB.RSField(reader, "Notes");

                    LanguageCode = DB.RSField(reader, "LanguageCode");
                    m_FirstName = DB.RSField(reader, "FirstName");
                    Salutation = DB.RSField(reader, "Salutation");
                    LastName = DB.RSField(reader, "LastName");
                    EMail = DB.RSField(reader, "Email");
                    Phone = DB.RSField(reader, "Phone");
                    WarehouseCode = DB.RSField(reader, "WarehouseCode");
                    m_SubscriptionExpiresOn = DB.RSFieldDateTime(reader, "SubscriptionExpDate");
                    _anonymousCustomerCode = DB.RSField(reader, "AnonymousCustomerCode");
                    _anonymousShipToCode = DB.RSField(reader, "AnonymousShipToCode");
                    CouponCode = DB.RSField(reader, "CouponCode");
                    m_CurrentSessionID = DB.RSFieldInt(reader, "CustomerSessionID");
                    m_LastActivity = DB.RSFieldDateTime(reader, "LastActivity");
                    _culture = CultureInfo.GetCultureInfo(this.LocaleSetting);
                    _over13 = DB.RSFieldBool(reader, "IsOver13");
                    _iscustomerAnonUpdated = (DB.RSFieldBool(reader, "IsUpdated"));
                    ContactCode = DB.RSField(reader, "ContactCode");
                    ContactFullName = DB.RSField(reader, "ContactFullName");
                    if (AppLogic.AppConfigBool("AllowCreditHold"))
                    {
                        IsCreditOnHold = false;
                    }
                    else
                    {
                        IsCreditOnHold = DB.RSFieldBool(reader, "IsCreditHold");
                    }
                    if (AppLogic.AppConfigBool("AllowProductFiltering"))
                    {
                        if (IsRegistered)
                            ProductFilterID = DB.RSFieldGUID(reader, "ProductFilterID");
                        else if (DB.RSField(reader, "ProductFilterID") == string.Empty)
                            ProductFilterID = Guid.Empty.ToString();
                        else
                            ProductFilterID = DB.RSFieldGUID(reader, "ProductFilterID");
                    }

                    if (DB.RSField(reader, "BusinessType").Equals(BusinessTypes.WholeSale.ToString(), StringComparison.InvariantCultureIgnoreCase))
                    {
                        BusinessType = BusinessTypes.WholeSale;
                    }
                    else
                    {
                        BusinessType = BusinessTypes.Retail;
                    }

                    TaxNumber = DB.RSField(reader, "TaxNumber");

                    bool emailformat = DB.RSFieldBool(reader, "IsOkToEmail");
                    if (emailformat)
                    {
                        OKToEMail = true;
                    }
                    else
                    {
                        OKToEMail = false;
                    }

                    if (!HasCustomerRecord)
                    {

                        string ls = string.Empty;

                        //For theading purpose
                        if (HttpContext.Current != null)
                        {
                            ls = CommonLogic.CookieCanBeDangerousContent(ro_LocaleSettingCookieName, true);
                        }

                        //get locale from cookie
                        LocaleSetting = CommonLogic.IIF(ls == "", LocaleSetting, ls);
                        LanguageCode = AppLogic.GetLanguageCode(LocaleSetting);
                    }
                }
            }
        }

        public string AnonymousCustomerCode
        {
            get { return _anonymousCustomerCode; }
        }

        public string AnonymousShipToCode
        {
            get { return _anonymousShipToCode; }
        }

        public Address GetPrimaryBillingAddress()
        {
            Address primaryBilling = new Address();
            primaryBilling.LoadByCustomer(this, AddressTypes.Billing);

            return primaryBilling;
        }

        public void ValidatePrimaryAddresses()
        {
            // sanity checker on address book for customer (invoked on account page):
            if (PrimaryBillingAddressID != String.Empty)
            {
                bool PrimaryBillingAddressFound = (DB.GetSqlN(String.Format("SELECT COUNT(*) AS N FROM Customer with (NOLOCK) WHERE CustomerCode = {0}", DB.SQuote(m_CustomerCode.ToString()))) > 0);
            }

            if (PrimaryShippingAddressID != String.Empty)
            {
                bool PrimaryShippingAddressFound = (DB.GetSqlN(String.Format("SELECT COUNT(*) AS N FROM CustomerShipToView with (NOLOCK) WHERE CustomerCode={0} AND SHIPTOCODE={1}", DB.SQuote(m_CustomerCode), DB.SQuote(PrimaryShippingAddressID))) > 0);
                if (!PrimaryShippingAddressFound)
                {

                    String AlternateShippingAddressID = String.Empty;

                    // try to find ANY other customer address (that does not have credit card info) to use in place of the one being deleted, if required:

                    using (SqlConnection con = DB.NewSqlConnection())
                    {
                        con.Open();
                        using (IDataReader rs = DB.GetRSFormat(con, String.Format("SELECT TOP 1 ShipToCode FROM CustomerShipToView with (NOLOCK) WHERE CustomerCode={0} AND SHIPTOCODE={1}", DB.SQuote(m_CustomerCode), DB.SQuote(PrimaryShippingAddressID))))
                        {
                            AlternateShippingAddressID = DB.RSField(rs, "shiptocode");
                        }
                    }


                    String BackupAddressID = String.Empty;

                    // try to find ANY other customer address as further backup, if required:

                    using (SqlConnection con = DB.NewSqlConnection())
                    {
                        con.Open();
                        using (IDataReader rs = DB.GetRSFormat(con, String.Format("SELECT TOP 1 ShipToCode FROM CustomerShipToView with (NOLOCK) WHERE CustomerCode={0} AND SHIPTOCODE={1}", DB.SQuote(m_CustomerCode), DB.SQuote(PrimaryShippingAddressID))))
                        {
                            if (rs.Read())
                            {
                                BackupAddressID = DB.RSField(rs, "AddressID");
                            }
                        }
                    }

                    if (AlternateShippingAddressID == String.Empty)
                    {
                        AlternateShippingAddressID = BackupAddressID;
                    }

                    DB.ExecuteSQL(String.Format("update Customer set ShippingAddressID={0} where CustomerID={1}", AlternateShippingAddressID.ToString(), m_CustomerCode.ToString()));

                    String sql = String.Format("UPDATE EcommerceShoppingCart SET ShippingAddressID={0} WHERE ShippingAddressID={1}", DB.SQuote(AlternateShippingAddressID), DB.SQuote(PrimaryShippingAddressID));
                    DB.ExecuteSQL(sql);
                }
            }
        }

        public bool OwnsThisAddress(String AddressID)
        {
            return Customer.OwnsThisAddress(m_CustomerCode, AddressID);
        }

        public void SetLocale(String preferredLocale)
        {
            preferredLocale = Localization.CheckLocaleSettingForProperCase(preferredLocale);
            if (preferredLocale.Length == 0)
            {
                preferredLocale = this.LocaleSetting;
            }

            if (IsRegistered)
            {
                String sql = String.Format("EcommerceUpdateLocale {0}, {1}, 1", DB.SQuote(preferredLocale), DB.SQuote(m_CustomerCode));
                DB.ExecuteSQL(sql);
            }
            if (!IsRegistered && HasCustomerRecord)
            {
                String sql = String.Format("EcommerceUpdateLocale {0}, {1}, 0", DB.SQuote(preferredLocale), DB.SQuote(m_CustomerCode));
                DB.ExecuteSQL(sql);
            }
            if (!HasCustomerRecord)
            {
                AppLogic.SetCookie(ro_LocaleSettingCookieName, preferredLocale, new TimeSpan(365, 0, 0, 0, 0));
            }

            this.LocaleSetting = preferredLocale;
        }


        public void SetCurrency(String CurrencySetting)
        {
            CurrencySetting = Localization.CheckCurrencySettingForProperCase(CurrencySetting);
            if (CurrencySetting.Length == 0)
            {
                CurrencySetting = Localization.GetPrimaryCurrency();
            }

            AppLogic.SetCookie(ro_CurrencySettingCookieName, CurrencySetting, new TimeSpan(365, 0, 0, 0, 0));
            m_CurrencyCode = CurrencySetting;
        }

        public String FullName
        {
            get { return this.Salutation + " " + (m_FirstName + " " + m_LastName).Trim(); }
        }

        static public String GetName(String CustomerID)
        {
            String tmpS = String.Empty;

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader rs = DB.GetRSFormat(con, "Select firstname,lastname from customer  with (NOLOCK) where CustomerID=" + CustomerID.ToString()))
                {
                    if (rs.Read())
                    {
                        tmpS = (DB.RSField(rs, "FirstName") + " " + DB.RSField(rs, "LastName")).Trim();
                    }
                }
            }

            return tmpS;
        }

        static public bool HasOrders(String CustomerID)
        {
            return (DB.GetSqlN("select count(ordernumber) as N from orders  with (NOLOCK) where customerid=" + CustomerID.ToString()) > 0);
        }

        public bool HasAtLeastOneAddress()
        {
            return Customer.HasAtLeastOneAddress(m_CustomerCode);
        }

        static public bool HasAtLeastOneAddress(String CustomerID)
        {
            return (DB.GetSqlN("SELECT COUNT(CustomerCode) AS N FROM Customer with (NOLOCK) WHERE CustomerCode=" + DB.SQuote(CustomerID.ToString())) > 0);
        }

        public bool HasOrders()
        {
            return Customer.HasOrders(m_CustomerCode);
        }

        public bool HasUsedCoupon(String couponCode)
        {
            return (DB.GetSqlN("SELECT COUNT(SalesOrderCode) AS N FROM CustomerSalesOrder with (NOLOCK) WHERE BillToCode=" + m_CustomerCode.ToString() + " AND LOWER(CouponCode)=" + DB.SQuote(couponCode.ToLower())) != 0);
        }

        static public bool HasUsedCoupon(String customerCode, String couponCode)
        {
            return (DB.GetSqlN("SELECT COUNT(SalesOrderCode) AS N FROM CustomerSalesOrder  with (NOLOCK) WHERE BillToCode=" + DB.SQuote(customerCode) + " AND LOWER(CouponCode)=" + DB.SQuote(couponCode.ToLowerInvariant())) != 0);
        }

        static public bool AnyCustomerHasUsedCoupon(String couponCode)
        {
            return (DB.GetSqlN("SELECT COUNT(SalesOrderCode) AS N FROM CustomerSalesOrder  with (NOLOCK) WHERE LOWER(CouponCode)=" + DB.SQuote(couponCode.ToLowerInvariant())) != 0);
        }

        static public bool CustomerCanAvailOfThisCoupon(String customerCode, String couponCode)
        {
            string couponID = string.Empty;

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader rs = DB.GetRSFormat(con, "SELECT CouponID FROM CustomerSalesCoupon with (NOLOCK) WHERE LOWER(CouponCode)=" + DB.SQuote(couponCode.ToLowerInvariant())))
                {
                    if (rs.Read())
                    {
                        couponID = DB.RSField(rs, "CouponID");
                    }
                }
            }

            return (DB.GetSqlN("SELECT COUNT(CustomerCode) AS N FROM CustomerCouponCustomer  with (NOLOCK) WHERE CustomerCode=" + DB.SQuote(customerCode) + " AND CouponID=" + DB.SQuote(couponID)) != 0);
        }

        static public bool StaticIsAdminSuperUser(String CustomerID)
        {
            String[] su = AppLogic.AppConfig("Admin_SuperUser").Split(',');
            for (int i = su.GetLowerBound(0); i <= su.GetUpperBound(0); i++)
            {
                if (CommonLogic.IsInteger(su[i]))
                {
                    if (Convert.ToString(Localization.ParseUSInt(su[i])) == CustomerID)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        static public bool StaticIsAdminUser(String CustomerID)
        {
            if (CustomerID == String.Empty)
            {
                return false;
            }
            bool tmp = false;

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader rs = DB.GetRSFormat(con, "select IsAdmin from customer with (NOLOCK) where CustomerID=" + CustomerID.ToString()))
                {
                    if (rs.Read())
                    {
                        tmp = DB.RSFieldBool(rs, "IsAdmin");
                    }
                }
            }

            return tmp;
        }

        private abstract class LoginLogic
        {
            protected Guid _id = Guid.Empty;

            protected LoginLogic(Guid id)
            {
                _id = id;
            }

            public Guid ID
            {
                get { return _id; }
            }
            public abstract bool Equals(string password);
        }

        private class MLImportedLoginLogic : LoginLogic
        {
            int _salt;
            string _pwdCypher = string.Empty;

            internal MLImportedLoginLogic(Guid id, int salt, string passwordCypher)
                : base(id)
            {
                _salt = salt;
                _pwdCypher = passwordCypher;
            }

            public override bool Equals(string password)
            {
                return InterpriseSuiteEcommerceCommon.Encrypt.ComputeSaltedHash(_salt, password) == _pwdCypher;
            }
        }

        private class InterpriseLoginLogic : LoginLogic
        {
            private string _customerCode = string.Empty;
            private string _password = string.Empty;
            private string _defaultContact = string.Empty;
            private string _contactCode = string.Empty;
            byte[] _salt = null;
            byte[] _iv = null;

            internal InterpriseLoginLogic(Guid id, string password, byte[] salt, byte[] iv)
                : base(id)
            {
                _password = password;
                _salt = salt;
                _iv = iv;
            }

            public string DefaultContact
            {
                get { return _defaultContact; }
                set { _defaultContact = value; }
            }

            public string ContactCode
            {
                get { return _contactCode; }
                set { _contactCode = value; }
            }

            public override int GetHashCode()
            {
                return base.ID.GetHashCode() + _password.GetHashCode();
            }

            public override bool Equals(string password)
            {
                // we need to have a valid id...
                if (Guid.Empty == _id)
                {
                    return false;
                }
                return InterpriseHelper.Encryption(password, _salt, _iv).Equals(_password);
            }
        }

        public static string GetDecryptedPassword(string email, string key)
        {
            string decryptedPword = string.Empty;
            string salt = string.Empty;
            string vector = string.Empty;

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, "SELECT cc.PasswordSalt, cc.PasswordIV FROM CRMContact cc with (NOLOCK) WHERE cc.Type = 'CustomerContact' AND cc.IsAllowWebAccess=1 AND cc.UserName = {0}", DB.SQuote(email)))
                {
                    while (reader.Read())
                    {
                        salt = DB.RSField(reader, "PasswordSalt");
                        vector = DB.RSField(reader, "PasswordIV");
                        decryptedPword = InterpriseHelper.Decryption(Convert.FromBase64String(key), Convert.FromBase64String(salt), Convert.FromBase64String(vector));
                    }
                }
            }

            return decryptedPword;
        }

        public static string GetEncryptedPassword(string email, string password)
        {
            string EncryptedPword = string.Empty;
            if (email.ToString() != null && password.ToString() != null)
            {

                using (SqlConnection con = DB.NewSqlConnection())
                {
                    con.Open();
                    using (IDataReader reader = DB.GetRSFormat(con, "SELECT cc.Password FROM CRMContact cc with (NOLOCK) WHERE cc.Type = 'CustomerContact' AND cc.IsAllowWebAccess=1 AND cc.UserName = {0}", DB.SQuote(email)))
                    {
                        while (reader.Read())
                        {
                            EncryptedPword = DB.RSField(reader, "Password");
                        }
                    }
                }
            }
            return EncryptedPword;
        }


        /// <summary>
        /// This is in support for multiple emails per login
        /// </summary>
        /// <param name="email"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public static Customer FindByLogin(string email, string password)
        {
            if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password)) return null;

            List<LoginLogic> availableLogins = new List<LoginLogic>();

            string loggedContactCode = string.Empty;

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, "SELECT c.DefaultContact, cc.ContactCode, cc.Password, cc.PasswordSalt, cc.PasswordIV, cc.ContactGUID FROM Customer c with (NOLOCK) INNER JOIN CRMContact cc with (NOLOCK) ON cc.Type = 'CustomerContact' AND cc.EntityCode = c.CustomerCode INNER JOIN EcommerceCustomerActiveSites ecas ON ecas.ContactCode = cc.ContactCode WHERE ecas.IsEnabled = 1 AND cc.IsAllowWebAccess=1 AND c.IsActive = 1 AND cc.IsActive = 1 AND cc.UserName = {0} AND ecas.WebsiteCode = {1} AND CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, ISNULL(cc.SubscriptionExpirationOn, GETDATE() + 1)))) >= CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, GETDATE()))) ORDER BY cc.DateCreated DESC", DB.SQuote(email), DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode)))
                {
                    while (reader.Read())
                    {
                        LoginLogic login = null;

                        try
                        {
                            InterpriseLoginLogic issiLogin =
                                new InterpriseLoginLogic(
                                new Guid(DB.RSFieldGUID(reader, "ContactGUID")),
                                DB.RSField(reader, "Password"),
                                Convert.FromBase64String(DB.RSField(reader, "PasswordSalt")),
                                Convert.FromBase64String(DB.RSField(reader, "PasswordIV"))
                            );

                            issiLogin.DefaultContact = DB.RSField(reader, "DefaultContact");
                            issiLogin.ContactCode = DB.RSField(reader, "ContactCode");
                            loggedContactCode = issiLogin.ContactCode;

                            login = issiLogin;
                        }
                        catch
                        {
                            // something could have happened.. like salt is null or empty string, in that case it's not a valid Base64 String

                            // this is guaranteed null if an exception has been thrown
                            // but let's make it explicit for readability...
                            login = null;
                        }

                        if (null != login)
                        {
                            availableLogins.Add(login);
                        }


                        try
                        {
                            int saltKey = 0;

                            if (int.TryParse(DB.RSField(reader, "PasswordSalt"), out saltKey))
                            {
                                login =
                                new MLImportedLoginLogic(
                                    new Guid(DB.RSFieldGUID(reader, "ContactGUID")),
                                    saltKey,
                                    DB.RSField(reader, "Password")
                                );
                            }
                        }
                        catch
                        {
                            // something could have happened.. like salt is null or empty string or not integer etc., in that case it's an invalid ML saltKey

                            // this is guaranteed null if an exception has been thrown
                            // but let's make it explicit for readability...
                            login = null;
                        }

                        if (null != login)
                        {
                            availableLogins.Add(login);
                        }
                    }
                }
            }

            if (availableLogins.Count == 0) return null;

            // now, let's start validating if our login is valid...
            foreach (LoginLogic login in availableLogins)
            {
                if (login.Equals(password))
                {
                    Customer foundCustomer = Customer.Find(login.ID);
                    return foundCustomer;
                }
            }
            // If we reached this part.. we didn't find any...
            return null;
        }

        public void RequireCustomerRecord()
        {
            if (!HasCustomerRecord)
            {
                MakeAnonCustomerRecord(out m_CustomerCode, out m_contactGUID);
                FormsAuthentication.SetAuthCookie(ContactGUID.ToString(), true);
                HttpCookie Cookie = HttpContext.Current.Response.Cookies[FormsAuthentication.FormsCookieName];
                Cookie.Expires = DateTime.Now.Add(new TimeSpan(1000, 0, 0, 0));

                Init();
            }
        }

        public void ReloadRegistered(Guid newRegisteredCustomerGuid)
        {
            if (this.HasCustomerRecord && this.IsNotRegistered)
            {
                m_contactGUID = newRegisteredCustomerGuid;

                Init();

                // make known to the authentication that this is registered
                FormsAuthentication.SetAuthCookie(newRegisteredCustomerGuid.ToString(), true);
            }
        }

        public void ReInitCustomerForActiveShoppers()
        {
            //Init();
            FormsAuthentication.SetAuthCookie(m_contactGUID.ToString(), true);
        }

        // check QS for an affiliateid= or affid=, and if so, set session Cookie
        // returns resulting active customer affiliateid (from QS or prior session Cookie)
        static public String RecordAffiliateSessionCookie()
        {
            String AffiliateID = String.Empty;
            String QS = CommonLogic.ServerVariables("QUERY_STRING").ToUpperInvariant();
            if (QS.IndexOf("AFFILIATEID=") != -1 || QS.IndexOf("AFFID=") != -1)
            {
                AffiliateID = CommonLogic.QueryStringCanBeDangerousContent("AffiliateID");
                if (AffiliateID == String.Empty)
                {
                    AffiliateID = CommonLogic.QueryStringCanBeDangerousContent("AffID");
                }
                AppLogic.SetSessionCookie("AffiliateID", AffiliateID.ToString());
            }
            else
            {
                // noting in QS, just return what their "prior" affiliateid is:
                AffiliateID = CommonLogic.CookieCanBeDangerousContent("AffiliateID", false);
            }
            return AffiliateID;
        }

        /// <summary>
        /// Clears the affiliate information on the cookie
        /// </summary>
        /// <returns></returns>
        public static void ClearAffiliateRecordFromCookie()
        {
            AppLogic.RemoveCookie("AffiliateID");
        }

        static public String RecordLocaleSettingCookie()
        {
            String LocaleSetting = String.Empty;
            String QS = CommonLogic.ServerVariables("QUERY_STRING").ToUpper();
            if (QS.IndexOf("LOCALESETTING=") != -1)
            {
                LocaleSetting = CommonLogic.QueryStringCanBeDangerousContent("LocaleSetting");
                if (LocaleSetting.Length == 0)
                {
                    LocaleSetting = Current.LocaleSetting;
                }
                if (LocaleSetting.IndexOf("<script>", StringComparison.InvariantCultureIgnoreCase) != -1)
                {
                    throw new ArgumentException("SECURITY EXCEPTION");
                }
                LocaleSetting = Localization.CheckLocaleSettingForProperCase(LocaleSetting);
                AppLogic.SetCookie(ro_LocaleSettingCookieName, LocaleSetting, new TimeSpan(1000, 0, 0, 0, 0));
            }
            else
            {
                // noting in QS, just return what their "prior" LocaleSetting is:
                LocaleSetting = CommonLogic.CookieCanBeDangerousContent(ro_LocaleSettingCookieName, true);
                LocaleSetting = Localization.CheckLocaleSettingForProperCase(LocaleSetting);
            }
            return LocaleSetting;
        }

        public bool IsLicensedUser()
        {
            if (IsNotRegistered)
            {
                return false;
            }
            int N = DB.GetSqlN("select count(*) as N from Orders with (NOLOCK) where TransactionState=" + DB.SQuote(AppLogic.ro_TXStateCaptured) + " and CustomerID=" + m_CustomerCode.ToString());
            return (N != 0);
        }
        // returns true if this address belongs to this customer
        static public bool OwnsThisAddress(String CustomerCode, String ShipToCode)
        {
            return (DB.GetSqlN("select count(*) as N from CustomerShipTo with (NOLOCK) WHERE CustomerCode=" + DB.SQuote(CustomerCode) + " and ShipToCode=" + DB.SQuote(ShipToCode)) > 0);
        }

        public bool OwnsThisOrder(string salesOrderCode)
        {
            string customerToCheck = this.CustomerCode;
            if (this.IsRegistered)
            {
                customerToCheck = this.CustomerCode;
            }
            else
            {
                if (this.IsNotRegistered && !this.IsUnregisteredAnonymous)
                {
                    customerToCheck = AnonymousCustomerCode;
                }
            }
            return (DB.GetSqlN("select count(*) as N from CustomerSalesOrder with (NOLOCK) WHERE BillToCode=" + DB.SQuote(customerToCheck) + " and SalesOrderCode=" + DB.SQuote(salesOrderCode)) > 0);
        }

        // make a new customer record and set SESSION Parms
        public static void MakeAnonCustomerRecord(out String customerCode, out Guid contactGuid)
        {
            customerCode = String.Empty;
            //customerGuid = Guid.Empty;
            contactGuid = Guid.Empty;
            String currencyCode = String.Empty;
            String newGuid = DB.GetNewGUID();
            String newContactGuid = DB.GetNewGUID();
            String affiliateID = Customer.RecordAffiliateSessionCookie();
            String localeSetting = String.Empty;

            string sWebSiteCode = InterpriseHelper.ConfigInstance.WebSiteCode;

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader rs = DB.GetRSFormat(con, "exec EcommerceGetAnonymousCustomerSettings @WebSiteCode={0}", DB.SQuote(sWebSiteCode)))
                {
                    if (rs.Read())
                    {
                        string preferredLocale = CommonLogic.CookieCanBeDangerousContent(ro_LocaleSettingCookieName, true);
                        localeSetting = CommonLogic.IIF(string.IsNullOrEmpty(preferredLocale), DB.RSField(rs, "LocaleSetting"), preferredLocale);
                        currencyCode = DB.RSField(rs, "CurrencyCode");
                    }
                }
            }

            // Insert a new record in the anonymous table
            using (SqlConnection con = new SqlConnection(DB.GetDBConn()))
            {
                using (SqlCommand cmdCreateAnon = new SqlCommand("EcommerceCreateAnonymousCustomer", con))
                {
                    cmdCreateAnon.CommandType = CommandType.StoredProcedure;

                    // CustomerGuid
                    SqlParameter paramCustomerGuid = new SqlParameter("@CustomerGuid", SqlDbType.UniqueIdentifier);
                    paramCustomerGuid.Value = new Guid(newGuid);
                    cmdCreateAnon.Parameters.Add(paramCustomerGuid);

                    // UserName
                    SqlParameter paramUserName = new SqlParameter("@UserName", SqlDbType.NVarChar, 100);
                    paramUserName.Value = string.Format("Anon_{0}", newGuid);
                    cmdCreateAnon.Parameters.Add(paramUserName);

                    // Password
                    SqlParameter paramPassword = new SqlParameter("@Password", SqlDbType.NVarChar, 100);
                    paramPassword.Value = "N/A";
                    cmdCreateAnon.Parameters.Add(paramPassword);

                    // Referrer
                    SqlParameter paramReferrer = new SqlParameter("@Referrer", SqlDbType.NVarChar, 100);
                    paramReferrer.Value = CommonLogic.CookieCanBeDangerousContent("Referrer", true);
                    cmdCreateAnon.Parameters.Add(paramReferrer);

                    // SalesRep
                    SqlParameter paramSalesRep = new SqlParameter("@SalesRep", SqlDbType.NVarChar, 30);
                    paramSalesRep.Value = CommonLogic.IsStringNullOrEmpty(affiliateID) ? "NULL" : affiliateID;
                    cmdCreateAnon.Parameters.Add(paramSalesRep);

                    // Locale Setting
                    SqlParameter paramLocaleSetting = new SqlParameter("@LocaleSetting", SqlDbType.NVarChar, 30);
                    paramLocaleSetting.Value = localeSetting;
                    cmdCreateAnon.Parameters.Add(paramLocaleSetting);

                    // currency code
                    SqlParameter paramCurrencyCode = new SqlParameter("@CurrencyCode", SqlDbType.NVarChar, 30);
                    paramCurrencyCode.Value = currencyCode;
                    cmdCreateAnon.Parameters.Add(paramCurrencyCode);

                    // last ip address
                    SqlParameter paramLastIPAddress = new SqlParameter("@LastIPAddress", SqlDbType.NVarChar, 20);
                    paramLastIPAddress.Value = CommonLogic.ServerVariables("REMOTE_ADDR");
                    cmdCreateAnon.Parameters.Add(paramLastIPAddress);

                    // ContactGuid
                    SqlParameter paramContactGuid = new SqlParameter("@ContactGuid", SqlDbType.UniqueIdentifier);
                    paramContactGuid.Value = new Guid(newContactGuid);
                    cmdCreateAnon.Parameters.Add(paramContactGuid);

                    con.Open();
                    cmdCreateAnon.ExecuteNonQuery();
                }
            }

            string makeAnonCustomerCodeSameAsIDCommand = string.Format("UPDATE EcommerceCustomer SET CustomerCode = CustomerID WHERE ContactGUID = {0}", DB.SQuote(newContactGuid));
            DB.ExecuteSQL(makeAnonCustomerCodeSameAsIDCommand);

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, "SELECT CustomerCode, ContactGUID FROM EcommerceCustomer with (NOLOCK) WHERE ContactGUID = {0}", DB.SQuote(newContactGuid)))
                {
                    if (reader.Read())
                    {
                        customerCode = DB.RSField(reader, "CustomerCode");
                        contactGuid = new Guid(DB.RSFieldGUID(reader, "ContactGUID"));
                    }
                }
            }

        }

        public string FormatBasedOnMyCurrency(decimal dAmount)
        {
            return InterpriseHelper.FormatCurrencyForCustomer(dAmount, this.CurrencyCode);
        }
        public String PricingLevel
        {
            get
            {
                return m_PricingLevel;
            }
            set
            {
                m_PricingLevel = value;
            }
        }

        /// <summary>
        /// Get the pricing method the customer is using.
        /// </summary>
        public String PricingMethod
        {
            get
            {
                return m_PricingMethod;
            }
            set
            {
                m_PricingMethod = value;
            }
        }

        /// <summary>
        /// Notes in Customer record.
        /// </summary>
        public String Notes
        {
            get
            {
                return m_Notes;
            }
            set
            {
                m_Notes = value;
            }
        }


        /// <summary>
        /// Get the default price customer is using.
        /// </summary>
        public String DefaultPrice
        {
            get
            {
                return m_DefaultPrice;
            }
            set
            {
                m_DefaultPrice = value;
            }
        }

        // overload for ML code compatibility
        public String CustomerID
        {
            get
            {
                return m_CustomerCode;
            }
            set
            {
                m_CustomerCode = value;
            }
        }

        public String CustomerCode
        {
            get
            {
                return m_CustomerCode;
            }
            set
            {
                m_CustomerCode = value;
            }
        }

        public bool IsRegistered
        {
            get
            {
                return m_IsRegistered;
            }
        }

        public bool IsNotRegistered
        {
            get { return !IsRegistered; }
        }

        public String PrimaryBillingAddressID
        {
            get
            {
                return m_DefaultBilToCode;
            }
            set
            {
                m_DefaultBilToCode = value;
            }
        }

        public String PrimaryShippingAddressID
        {
            get
            {
                return m_DefaultShipToCode;
            }
            set
            {
                m_DefaultShipToCode = value;
            }
        }

        public int SkinID
        {
            get
            {
                return m_SkinID;
            }
            set
            {
                m_SkinID = value;
            }
        }

        public DateTime LastActivity
        {
            get { return m_LastActivity; }
        }

        public bool OKToEMail
        {
            get
            {
                return m_OKToEMail;
            }
            set
            {
                m_OKToEMail = value;
            }
        }

        public String CouponCode
        {
            get
            {
                return m_CouponCode;
            }
            set
            {
                m_CouponCode = value;
            }
        }

        public String LastIPAddress
        {
            get
            {
                return m_LastIPAddress;
            }
        }
        public String Phone
        {
            get
            {
                return m_Phone;
            }
            set
            {
                m_Phone = value;
            }
        }

        public String AffiliateID
        {
            get
            {
                return m_AffiliateID;
            }
        }

        public bool HasCustomerRecord
        {
            get
            {
                return m_HasCustomerRecord;
            }
        }

        public String Password
        {
            get
            {
                return m_Password;
            }
            set
            {
                m_Password = value;
            }
        }

        public String EMail
        {
            get
            {
                return m_EMail;
            }
            set
            {
                m_EMail = value;
            }
        }

        public Guid ContactGUID
        {
            get
            {
                return m_contactGUID;
            }
        }

        public String FirstName
        {
            get
            {
                return m_FirstName;
            }
            set
            {
                m_FirstName = value;
            }
        }

        public String LastName
        {
            get
            {
                return m_LastName;
            }
            set
            {
                m_LastName = value;
            }
        }

        public String PaymentMethod
        {
            get
            {
                return _paymentMethod;
            }
        }

        public String LocaleSetting
        {
            get
            {
                return m_LocaleSetting;
            }
            protected set
            {
                //Set the local setting and then verify that it's a valid value.
                m_LocaleSetting = value;

                //See if the current locale is in the list of enabled selling languages.
                DataSet ds = DB.GetDS(string.Format("SELECT * FROM eCommerceWebLocaleView with (NOLOCK) WHERE ShortString = '{0}'", m_LocaleSetting), false);

                if (ds.Tables[0].Rows.Count == 0)
                {
                    //The locale was not found in the list so we need to get the company default. 
                    //This is always garanteed to be in the selling language list.
                    ds = null;
                    ds = DB.GetDS("SELECT ShortString FROM SystemLanguage tSysLang with (NOLOCK) JOIN SystemCompanyInformation tCompany with (NOLOCK) ON tSysLang.LanguageCode = tCompany.CompanyLanguage", false);

                    if (ds.Tables[0].Rows.Count > 0)
                    {
                        //We found a row so get the company's locale.
                        m_LocaleSetting = ds.Tables[0].Rows[0]["ShortString"].ToString();
                    }
                    else
                    {
                        //This else should never happend but just incase we will default to english us.
                        m_LocaleSetting = "en-US";
                    }
                }

                //Make sure it has proper casing.
                m_LocaleSetting = Localization.CheckLocaleSettingForProperCase(m_LocaleSetting);
            }
        }

        public String CurrencyCode
        {
            get
            {
                return m_CurrencyCode;
            }
        }

        public DateTime SubscriptionExpiresOn
        {
            get
            {
                return m_SubscriptionExpiresOn;
            }
        }

        public string Roles
        {
            get { return m_Roles; }
        }

        public decimal Discount
        {
            get { return _discount; }
            set { _discount = value; }
        }

        public string DiscountBand
        {
            get { return _discountBand; }
            set { _discountBand = value; }
        }
        public decimal PricingPercent
        {
            get { return _pricingPercent; }
            set { _pricingPercent = value; }
        }

        public string DiscountType
        {
            get { return _discountType; }
            set { _discountType = value; }
        }

        public CustomerSession ThisCustomerSession
        {
            get
            {
                if (!HasCustomerRecord)
                {
                    m_CustomerSession = new CustomerSession();
                }
                else if (m_CurrentSessionID == -1)
                {
                    // make customer record for this one...
                    m_CustomerSession = CustomerSession.CreateCustomerSession(this.ContactGUID, "", "", m_LastIPAddress);
                    m_CurrentSessionID = m_CustomerSession.SessionID;
                }
                else
                {
                    if (m_CustomerSession == null)
                    {
                        m_CustomerSession = new CustomerSession(m_CurrentSessionID, false);
                        m_CurrentSessionID = m_CustomerSession.SessionID;
                    }
                }
                return m_CustomerSession;
            }
        }

        public bool IsRequestingFullModeFromMobile()
        {
            return FullModeInMobile;
        }

        public bool Register(Address sameBillingAndShippingAddress, bool checkOutMode)
        {
            return Register(sameBillingAndShippingAddress, sameBillingAndShippingAddress, checkOutMode);
        }

        public class CustomerRegistrationException : ApplicationException
        {
            public CustomerRegistrationException(string message) : this(message, null) { }
            public CustomerRegistrationException(string message, Exception innerException) : base(message, innerException) { }
        }

        public bool Register(Address billingAddress, Address shippingAddress, bool checkOutMode)
        {
            string message = "An error has occured while creating your account....";

            // NOTE:
            //  This call should be made if the customer is an anonymous that's recorded
            //  in the anonymous table...
            if (this.IsNotRegistered && !this.IsUnregisteredAnonymous)
            {
                string appliedDefaultPrice = this.DefaultPrice; // initially would default to the setting of the anonymous customer...

                switch (this.BusinessType)
                {
                    case BusinessTypes.Retail:
                        appliedDefaultPrice = Interprise.Framework.Base.Shared.Const.BUSINESS_TYPE_RETAIL;
                        break;
                    case BusinessTypes.WholeSale:
                        appliedDefaultPrice = Interprise.Framework.Base.Shared.Const.BUSINESS_TYPE_WHOLESALE;
                        break;
                }

                using (NewCustomerDetailDatasetGateway newCustomerDataset = new NewCustomerDetailDatasetGateway())
                {
                    using (NewCustomerDetailFacade newCustomerFacade = new NewCustomerDetailFacade(newCustomerDataset))
                    {
                        try
                        {
                            newCustomerFacade.AddressType = Interprise.Framework.Base.Shared.Enum.NewCustomerAddressType.DifferentBillToAndShipToAddress;
                            newCustomerFacade.AddCustomer(Interprise.Framework.Base.Shared.Const.TEMPORARY_DOCUMENTCODE, billingAddress.Company,
                                                          true, appliedDefaultPrice);

                            // NOTE :
                            //  This should assign the default class template based on the
                            //  post code and country of the user
                            newCustomerFacade.AssignDefaultClassTemplate(appliedDefaultPrice, false);
                            NewCustomerDetailDatasetGateway.CustomerViewRow newCustomerRow = newCustomerDataset.CustomerView[0];
                            newCustomerRow.BeginEdit();
                            newCustomerRow.AssignedTo = InterpriseHelper.ConfigInstance.UserCode;
                            newCustomerRow.CustomerName = billingAddress.Company;
                            newCustomerRow.CustomerGUID = Guid.NewGuid();
                            newCustomerRow.LastIPAddress = CommonLogic.ServerVariables("REMOTE_ADDR");
                            newCustomerRow.Address = billingAddress.Address1;
                            newCustomerRow.City = billingAddress.City;
                            newCustomerRow.State = billingAddress.State;
                            newCustomerRow.County = billingAddress.County;
                            newCustomerRow.Country = billingAddress.Country;
                            newCustomerRow.Telephone = billingAddress.Phone;
                            newCustomerRow.Email = billingAddress.EMail;
                            newCustomerRow.AddressType = billingAddress.ResidenceType.ToString();
                            newCustomerRow.BusinessType = this.BusinessType.ToString();
                            newCustomerRow.TaxNumber = this.TaxNumber;
                            newCustomerRow.IsProspect = true;
                            newCustomerRow.Over13Checked = this.IsOver13;
                            newCustomerRow.FirstName = billingAddress.FirstName;
                            newCustomerRow.LastName = billingAddress.LastName;

                            // Get the default from the setting
                            NewCustomerDetailDatasetGateway.CustomerShipToViewRow newCustomerShipToRow = newCustomerDataset.CustomerShipToView[0];
                            newCustomerShipToRow.BeginEdit();
                            newCustomerShipToRow.ShipToName = shippingAddress.Company;
                            newCustomerShipToRow.Email = billingAddress.EMail; // Make it default to the Customer Email!!!
                            newCustomerShipToRow.WebSite = string.Empty;
                            newCustomerShipToRow.Address = shippingAddress.Address1;
                            newCustomerShipToRow.City = shippingAddress.City;
                            newCustomerShipToRow.State = shippingAddress.State;
                            newCustomerShipToRow.County = shippingAddress.County;
                            newCustomerShipToRow.Country = shippingAddress.Country;
                            newCustomerShipToRow.Telephone = shippingAddress.Phone;
                            newCustomerShipToRow.AddressType = shippingAddress.ResidenceType.ToString();

                            // reset the class template once the country and postal code is applied...
                            newCustomerFacade.AssignDefaultClassTemplate(appliedDefaultPrice, false);
                            newCustomerRow.SourceCode = SourceCode;

                            // Now for the Webstore Anonymous settings as Template
                            // NOTE :   Since we are at this moment still carrying
                            //          the anonymous customer settings, those should apply here
                            newCustomerRow.DefaultPrice = this.DefaultPrice;
                            newCustomerRow.PricingMethod = this.PricingMethod;
                            newCustomerRow.PricingLevel = this.PricingLevel;
                            newCustomerRow.PricingPercent = this.PricingPercent;
                            newCustomerRow.DiscountType = this.DiscountType;
                            newCustomerRow.Discount = this.Discount;
                            newCustomerRow.DiscountBand = this.DiscountBand;

                            ContactDatasetGateway contactDataset = new ContactDatasetGateway();
                            ContactDatasetGateway.CRMContactViewRow newContactRow = contactDataset.CRMContactView.NewCRMContactViewRow();

                            newContactRow.BeginEdit();
                            newContactRow.EntityCode = Interprise.Framework.Base.Shared.Const.TEMPORARY_DOCUMENTCODE;
                            newContactRow.ContactFullName = billingAddress.FirstName + " " + billingAddress.LastName;
                            newContactRow.ContactFirstName = billingAddress.FirstName;
                            newContactRow.ContactLastName = billingAddress.LastName;
                            newContactRow.ContactSalutationCode = this.Salutation;
                            newContactRow.BusinessPhone = billingAddress.Phone;
                            newContactRow.Type = Interprise.Framework.Base.Shared.Enum.TransactionType.CustomerContact.ToString();
                            newContactRow.ContactCode = Interprise.Framework.Base.Shared.Const.TEMPORARY_DOCUMENTCODE;
                            newContactRow.ContactGUID = Guid.NewGuid();
                            // NOTE:
                            //  We now use Email1 as username since it has a longer length
                            newContactRow.Email1 = billingAddress.EMail;
                            newContactRow.Username = billingAddress.EMail;
                            newContactRow.WebSiteCode = InterpriseHelper.ConfigInstance.WebSiteCode;

                            if (ResidenceTypes.Residential == billingAddress.ResidenceType)
                            {
                                newContactRow.HomePhone = billingAddress.Phone;
                            }

                            byte[] salt = InterpriseHelper.GenerateSalt();
                            byte[] iv = InterpriseHelper.GenerateVector();
                            string passwordCypher = InterpriseHelper.Encryption(this.Password, salt, iv);

                            newContactRow.Password = passwordCypher;
                            newContactRow.PasswordSalt = Convert.ToBase64String(salt);
                            newContactRow.PasswordIV = Convert.ToBase64String(iv);
                            newContactRow.IsActive = true;
                            newContactRow.IsAllowWebAccess = true;
                            newContactRow.Address = billingAddress.Address1;
                            newContactRow.City = billingAddress.City;
                            newContactRow.County = billingAddress.County;
                            newContactRow.Country = billingAddress.Country;
                            newContactRow.LanguageCode = CountryAddressDTO.GetLanguageCode(billingAddress.Country);
                            newContactRow.EmailRule = CommonLogic.IIF(this.IsOKToEMail, "AllEmails", "NoticesOnly");
                            newContactRow.IsOkToEmail = CommonLogic.IIF(this.IsOKToEMail, true, false);
                            if (newCustomerRow["ProductFilterID"] == System.DBNull.Value) { newCustomerRow.ProductFilterID = System.Guid.Empty; }
                            newContactRow.ProductFilterID = newCustomerRow.ProductFilterID;

                            #region Customer / CRMContact Table Postal Code Handler

                            string postal = String.Empty;
                            int billingPostalPlus4 = 0;

                            if (billingAddress.Country == DomainConstants.COUNTRY_US)
                            {
                                int digits = InterpriseHelper.GetPostalCodeDigits(billingAddress.PostalCode, false);
                                postal = CommonLogic.IIF(digits == 0, billingAddress.PostalCode, digits.ToString("00000.##"));

                                billingPostalPlus4 = InterpriseHelper.GetPostalCodeDigits(billingAddress.PostalCode, true);
                                if (billingPostalPlus4 > 0)
                                {
                                    newCustomerRow.Plus4 = billingPostalPlus4;
                                    newContactRow.Plus4  = billingPostalPlus4;
                                }
                            }
                            else
                            {
                                postal = billingAddress.PostalCode;
                            }

                            newCustomerRow.PostalCode = postal;
                            newContactRow.PostalCode = postal;

                            #endregion

                            #region CustomerShipTo Postal Code Handler

                            postal = String.Empty;

                            if (shippingAddress.Country == DomainConstants.COUNTRY_US)
                            {
                                int digits = InterpriseHelper.GetPostalCodeDigits(shippingAddress.PostalCode, false);
                                postal = CommonLogic.IIF(digits == 0, shippingAddress.PostalCode, digits.ToString("00000.##"));

                                int postalPlus4 = InterpriseHelper.GetPostalCodeDigits(shippingAddress.PostalCode, true);
                                if (postalPlus4 > 0)
                                {
                                    newCustomerShipToRow.Plus4 = postalPlus4;
                                }
                            }
                            else
                            {
                                postal = shippingAddress.PostalCode;
                            }

                            newCustomerShipToRow.PostalCode = postal;

                            #endregion

                            newContactRow.EndEdit();
                            newCustomerRow.EndEdit();
                            newCustomerShipToRow.EndEdit();

                            contactDataset.CRMContactView.AddCRMContactViewRow(newContactRow);

                            newCustomerFacade.DefaultContactDataset = contactDataset;

                            string[][] commands = new string[][] { 
                                                        new string[] { newCustomerDataset.CustomerView.TableName, 
                                                            Interprise.Framework.Base.Shared.StoredProcedures.CREATECUSTOMER, 
                                                            Interprise.Framework.Base.Shared.StoredProcedures.UPDATECUSTOMER, 
                                                            Interprise.Framework.Base.Shared.StoredProcedures.DELETECUSTOMER }, 
                                                        new String[] { newCustomerDataset.CustomerShipToView.TableName, 
                                                            Interprise.Framework.Base.Shared.StoredProcedures.CREATECUSTOMERSHIPTO, 
                                                            Interprise.Framework.Base.Shared.StoredProcedures.UPDATECUSTOMERSHIPTO, 
                                                            Interprise.Framework.Base.Shared.StoredProcedures.DELETECUSTOMERSHIPTO }, 
                                                        new String[] { 
                                                            newCustomerDataset.CustomerAccount.TableName, 
                                                            Interprise.Framework.Base.Shared.StoredProcedures.CREATECUSTOMERACCOUNT, 
                                                            Interprise.Framework.Base.Shared.StoredProcedures.UPDATECUSTOMERACCOUNT, 
                                                            Interprise.Framework.Base.Shared.StoredProcedures.DELETECUSTOMERACCOUNT }, 
                                                        new string[] { 
                                                            newCustomerDataset.CustomerShipToAccount.TableName, 
                                                            Interprise.Framework.Base.Shared.StoredProcedures.CREATECUSTOMERACCOUNT, 
                                                            Interprise.Framework.Base.Shared.StoredProcedures.UPDATECUSTOMERACCOUNT, 
                                                            Interprise.Framework.Base.Shared.StoredProcedures.DELETECUSTOMERACCOUNT }};

                            // Commit the records to the database....
                            newCustomerFacade.UpdateDataSet(
                                commands,
                                Interprise.Framework.Base.Shared.Enum.TransactionType.CustomerDetail,
                                string.Empty,
                                false
                            );

                            // NOTE : Every step here has to be successful!!!
                            if (newCustomerDataset.HasErrors) throw new CustomerRegistrationException(message);
                            if (contactDataset.HasErrors) throw new CustomerRegistrationException(message);

                            // Finalize all changes...
                            newContactRow.AcceptChanges();

                            newCustomerRow = newCustomerDataset.CustomerView[0];
                            newCustomerShipToRow = newCustomerDataset.CustomerShipToView[0];

                            newCustomerRow.DefaultAPContact = newCustomerFacade.CurrentDataset.Tables["CRMContactView"].Rows[0]["ContactCode"].ToString();
                            newCustomerRow.DefaultContact = newCustomerFacade.CurrentDataset.Tables["CRMContactView"].Rows[0]["ContactCode"].ToString();
                            newCustomerRow.DefaultShipToCode = newCustomerShipToRow.ShipToCode;

                            newCustomerFacade.DefaultContactDataset = null;
                            newCustomerFacade.DefaultShipToContactDataset = null;
                            newCustomerFacade.DefaultAPContactDataset = null;

                            newCustomerFacade.UpdateDataSet(
                                commands,
                                Interprise.Framework.Base.Shared.Enum.TransactionType.CustomerDetail,
                                string.Empty,
                                false
                            );

                            // NOTE : Every step here has to be successful!!!
                            if (newCustomerDataset.HasErrors) throw new CustomerRegistrationException(message);

                            string billingCode = string.Empty;
                            InterpriseHelper.AddCustomerBillToInfo(newCustomerRow.CustomerCode, true);


                            string defaultBillingCode = string.Empty;
                            using (SqlConnection con = DB.NewSqlConnection())
                            {
                                con.Open();
                                using (IDataReader reader = DB.GetRSFormat(con, "SELECT CreditCardCode FROM Customer with (NOLOCK) WHERE CustomerCode = {0}", DB.SQuote(newCustomerRow.CustomerCode)))
                                {
                                    if (reader.Read())
                                    {
                                        defaultBillingCode = DB.RSField(reader, "CreditCardCode");
                                    }
                                }
                            }

                            // Update Anon record...
                            string updateAnonCommand =
                            string.Format(
                                "UPDATE EcommerceCustomer SET UserName={0}, Password={1}, CustomerCode={2}, CustomerGuid = {3}, Telephone={4}, ContactGuid = {5} WHERE CustomerID={6}",
                                DB.SQuote(billingAddress.EMail),
                                DB.SQuote(passwordCypher),
                                DB.SQuote(newCustomerRow.CustomerCode),
                                DB.SQuote(newCustomerRow.CustomerGUID.ToString()),
                                DB.SQuote(billingAddress.Phone),
                                DB.SQuote(newContactRow.ContactGUID.ToString()),
                                this.CustomerCode
                            );

                            DB.ExecuteSQL(updateAnonCommand);

                            string updateContact =
                            string.Format(
                                "UPDATE CRMContact SET DefaultBillingCode = {0}, DefaultShippingCode = {1} WHERE ContactGUID ={2}",
                                DB.SQuote(defaultBillingCode),
                                DB.SQuote(newCustomerDataset.CustomerShipToView[0].ShipToCode.ToString()),
                                DB.SQuote(newContactRow.ContactGUID.ToString())
                            );
                            DB.ExecuteSQL(updateContact);

                            if (checkOutMode)
                            {
                                string updateShoppingCartCommand =
                                 string.Format(
                                 "UPDATE EcommerceShoppingCart SET CustomerCode = {0}, ContactCode = {1} where CustomerCode = {2}",
                                 DB.SQuote(newCustomerRow.CustomerCode),
                                 DB.SQuote(newCustomerRow.DefaultContact),
                                 DB.SQuote(this.CustomerCode)
                             );

                                DB.ExecuteSQL(updateShoppingCartCommand);

                                // update kit items in cart if there is any....
                                string updateKitCommand =
                                string.Format(
                                    "UPDATE EcommerceKitCart SET CustomerCode = {0} WHERE CustomerCode = {1}",
                                    DB.SQuote(newCustomerRow.CustomerCode),
                                    DB.SQuote(this.CustomerCode)
                                );

                                DB.ExecuteSQL(updateKitCommand);

                                if (this.CouponCode != null)
                                {
                                    string updateCustomerCoupon = string.Format("UPDATE Customer SET CouponCode = {0} WHERE CustomerCode = {1}", DB.SQuote(this.CouponCode), DB.SQuote(newCustomerRow.CustomerCode));
                                    DB.ExecuteSQL(updateCustomerCoupon);
                                }
                            }

                            // Refresh this info...
                            this.ReloadRegistered(newContactRow.ContactGUID);

                            InterpriseHelper.CreateContactValidSites(this);

                            CustomerDA.UpdateCustomerCreditCardPlus4Field(defaultBillingCode, billingPostalPlus4);

                        }
                        catch (Exception ex)
                        {
                            // a general error.... inform account not created or an error while creating...
                            throw new CustomerRegistrationException(ex.GetBaseException().ToString());
                        }
                    }
                }
                return true;
            }

            return false;
        }

        public string GetPassword()
        {
            return GetPassword(this.ContactCode);
        }

        public string GetPassword(string contactCode)
        {
            string password = string.Empty;

            try
            {
                string pwd64, salt64, iv64;
                pwd64 = salt64 = iv64 = string.Empty;

                using (SqlConnection con = DB.NewSqlConnection())
                {
                    con.Open();
                    using (IDataReader reader = DB.GetRSFormat(con, "SELECT Password, PasswordSalt, PasswordIV FROM CRMContact with (NOLOCK) WHERE ContactCode = {0}", DB.SQuote(contactCode)))
                    {
                        if (reader.Read())
                        {
                            pwd64 = DB.RSField(reader, "Password");
                            salt64 = DB.RSField(reader, "PasswordSalt");
                            iv64 = DB.RSField(reader, "PasswordIV");
                        }
                    }
                }

                byte[] pwd = Convert.FromBase64String(pwd64);
                byte[] salt = Convert.FromBase64String(salt64);
                byte[] iv = Convert.FromBase64String(iv64);

                password = InterpriseHelper.Decryption(pwd, salt, iv);
            }
            catch
            {
                password = string.Empty;
            }

            return password;
        }

        public void ClearTransactions(bool clearGatewayLastError)
        {
            AppLogic.ClearCardExtraCodeInSession(this);

            if (clearGatewayLastError)
            {
                this.ThisCustomerSession.ClearVal("LastGatewayErrorMessage");
            }
        }

        public string LastGatewayErrorMessage
        {
            get { return ThisCustomerSession["LastGatewayErrorMessage"]; }
            set { ThisCustomerSession["LastGatewayErrorMessage"] = value; }
        }

        public int FailedTransactionCount
        {
            get
            {
                return ThisCustomerSession.SessionUSInt("FailedTransactionCount");
            }
            set
            {
                ThisCustomerSession.SetVal("FailedTransactionCount", value.ToString());
            }
        }

        public void IncrementFailedTransactionCount()
        {
            this.FailedTransactionCount += 1;
        }

        public void ResetFailedTransactionCount()
        {
            this.FailedTransactionCount = 0;
        }

        public void Update()
        {
            if (this.IsRegistered)
            {
                using (SqlConnection con = new SqlConnection(DB.GetDBConn()))
                {
                    using (SqlCommand cmdUpdateCustomer = new SqlCommand("eCommerceUpdateCustomer", con))
                    {
                        cmdUpdateCustomer.CommandType = CommandType.StoredProcedure;

                        SqlParameter paramCustomerCode = new SqlParameter("@ContactGuid", SqlDbType.UniqueIdentifier);
                        paramCustomerCode.Value = this.ContactGUID;
                        cmdUpdateCustomer.Parameters.Add(paramCustomerCode);

                        SqlParameter paramFirstName = new SqlParameter("@FirstName", SqlDbType.NVarChar, 50);
                        paramFirstName.Value = this.FirstName;
                        cmdUpdateCustomer.Parameters.Add(paramFirstName);

                        SqlParameter paramLastName = new SqlParameter("@LastName", SqlDbType.NVarChar, 50);
                        paramLastName.Value = this.LastName;
                        cmdUpdateCustomer.Parameters.Add(paramLastName);

                        SqlParameter paramSalutation = new SqlParameter("@SalutationCode", SqlDbType.NVarChar, 30);
                        paramSalutation.Value = this.Salutation;
                        cmdUpdateCustomer.Parameters.Add(paramSalutation);

                        SqlParameter paramEmail = new SqlParameter("@Email", SqlDbType.NVarChar, 50);
                        paramEmail.Value = this.EMail;
                        cmdUpdateCustomer.Parameters.Add(paramEmail);

                        SqlParameter paramPhone = new SqlParameter("@Phone", SqlDbType.NVarChar, 50);
                        paramPhone.Value = this.Phone;
                        cmdUpdateCustomer.Parameters.Add(paramPhone);

                        SqlParameter paramIsOver13 = new SqlParameter("@IsOver13", SqlDbType.Bit);
                        paramIsOver13.Value = this.IsOver13;
                        cmdUpdateCustomer.Parameters.Add(paramIsOver13);

                        SqlParameter paramEmailRule = new SqlParameter("@EmailRule", SqlDbType.NVarChar, 20);
                        paramEmailRule.Value = CommonLogic.IIF(this.IsOKToEMail, "AllEmails", "NoticesOnly");
                        cmdUpdateCustomer.Parameters.Add(paramEmailRule);

                        SqlParameter paramIsOkToEmail = new SqlParameter("@IsOkToEmail", SqlDbType.Bit);
                        paramIsOkToEmail.Value = CommonLogic.IIF(this.IsOKToEMail, true, false);
                        cmdUpdateCustomer.Parameters.Add(paramIsOkToEmail);

                        SqlParameter paramBusinessType = new SqlParameter("@BusinessType", SqlDbType.NVarChar, 30);
                        paramBusinessType.Value = this.BusinessType.ToString();
                        cmdUpdateCustomer.Parameters.Add(paramBusinessType);

                        SqlParameter paramTaxNumber = new SqlParameter("@TaxNumber", SqlDbType.NVarChar, 50);
                        paramTaxNumber.Value = this.TaxNumber;
                        cmdUpdateCustomer.Parameters.Add(paramTaxNumber);

                        SqlParameter paramPassword = new SqlParameter("@Password", SqlDbType.NVarChar, 50);
                        SqlParameter paramSalt = new SqlParameter("@PasswordSalt", SqlDbType.NVarChar, 50);
                        SqlParameter paramIV = new SqlParameter("@PasswordIV", SqlDbType.NVarChar, 50);

                        cmdUpdateCustomer.Parameters.Add(paramPassword);
                        cmdUpdateCustomer.Parameters.Add(paramSalt);
                        cmdUpdateCustomer.Parameters.Add(paramIV);

                        bool shouldUpdatePassword = !this.Password.Equals(AppLogic.PasswordValuePlaceHolder);
                        if (shouldUpdatePassword)
                        {
                            byte[] salt = InterpriseHelper.GenerateSalt();
                            byte[] iv = InterpriseHelper.GenerateVector();
                            string passwordCypher = InterpriseHelper.Encryption(this.Password, salt, iv);

                            paramPassword.Value = passwordCypher;
                            paramSalt.Value = Convert.ToBase64String(salt);
                            paramIV.Value = Convert.ToBase64String(iv);
                        }
                        else
                        {
                            paramPassword.Value = DBNull.Value;
                            paramSalt.Value = DBNull.Value;
                            paramIV.Value = DBNull.Value;
                        }

                        con.Open();
                        cmdUpdateCustomer.ExecuteNonQuery();
                    }
                }
            }
        }

        #region IIdentity Members
        [XmlIgnore]
        public bool IsAuthenticated
        {
            get
            {
                return ((this.ContactGUID != null) && (!this.ContactGUID.Equals("")));
            }
        }

        [XmlIgnore]
        public string Name
        {
            get
            {
                return this.ContactGUID.ToString();
            }
        }

        [XmlIgnore]
        public string AuthenticationType
        {
            get
            {
                return "Forms";
            }
        }
        #endregion

        public static Customer Current
        {
            get
            {
                if (null != HttpContext.Current)
                {
                    InterpriseSuiteEcommercePrincipal principal = HttpContext.Current.User as InterpriseSuiteEcommercePrincipal;
                    //This will handle error when getting Customer details connecting to SQL.
                    if (principal == null)
                    {
                        return null;
                    }
                    return principal.ThisCustomer;
                }
                return null;
            }
        }

        public bool FullModeInMobile
        {
            get
            {
                //save the last record of fullmode
                bool? isRequestedFullMode = (ThisCustomerSession[DomainConstants.MOBILE_FULLMODE_QUERYTSTRING].TryParseBool());
                return (isRequestedFullMode.HasValue) ? isRequestedFullMode.Value : false;
            }
            set
            {
                ThisCustomerSession[DomainConstants.MOBILE_FULLMODE_QUERYTSTRING] = value.ToString();
            }
        }

        public bool IsInEditingMode() {
            bool? isEditMode = this.ThisCustomerSession[DomainConstants.CMS_ENABLE_EDITMODE].TryParseBool();
            return (isEditMode.HasValue && isEditMode.Value);
        }

        public IEnumerable<GiftRegistry> GiftRegistries
        {
            get
            {
                return GiftRegistryDA.GetAllGiftRegistries(ContactGUID, InterpriseHelper.ConfigInstance.WebSiteCode, Culture);
            }
        }

        
    }

}